#ifndef __DATA_FIELD_HH__
#define __DATA_FIELD_HH__
#include <string.h>
#include <sstream>
#include <iterator>
#include <string>
using namespace std;
#include <misc/error.h>
#include <dyntype/dynobject.h>
#include <dataspace/axes.h>
#include "ndim-utils.h"
#include "mmap-utils.h"

class DataField;
class PrintCB : public NDimRangeTraverseCB
{
public:
  ostream* out;
  const DataField* field;
  PrintCB(ostream& out, const DataField* field);
  void do_it(const vector<data_index_t>& coor);
};

class DataField
{
public:
  DataField();
  virtual ~DataField();
  void init(DynType* dyntype, const DynObject& dflt_value);

  DynType* get_value_dyntype() const;
  const DynObject& get_dflt_value() const;
  const vector<data_index_t>& get_shape() const;

  void dump() const;
  virtual void print(ostream&) const = 0;

  virtual string get_filename() const = 0;

  virtual void save() const = 0;
  virtual void load(const string& fn, bool open_writable) = 0;

  virtual void get_value(const vector<data_index_t>& data_coor, 
			 DynObject* value) const = 0;
  virtual void set_value(const vector<data_index_t>& data_coors,
			 const DynObject& value) = 0;
  virtual bool is_none_value(const vector<data_index_t>& data_coors) const = 0;

  virtual void allocate_indexes(size_t i_dim, size_t n, 
				vector<data_index_t>* new_indexes) = 0;
  virtual void delete_indexes(size_t i_dim, 
			      const vector<data_index_t>& del_indexes) = 0;

protected:
  vector<data_index_t> shape;
  DynType* value_dyntype;
  DynObject dflt_value;
};

// ...............................................................

class MMapDataField : public DataField
{
 public:
  MMapDataField();
  MMapDataField(DynType* value_dyntype,
		const vector<data_index_t>& max_shape,
		const char* fn,
		bool open_writable);

  void print(ostream&) const;
  string get_filename() const;  
  void get_value(const vector<data_index_t>& data_coor, DynObject* v) const; 
  void set_value(const vector<data_index_t>& data_coor,
		 const DynObject& value);
  bool is_none_value(const vector<data_index_t>& data_coors) const;
  void allocate_indexes(size_t i_dim, size_t n, 
			vector<data_index_t>* new_indexes);
  void delete_indexes(size_t i_dim, 
		      const vector<data_index_t>& del_indexes);
  void save() const;
  void load(const string& fn, bool open_writable);

 private:
  vector<data_index_t> max_shape;
  MMap mmap_data;
  char* data;

  void init__(DynType* value_dyntype,
	      const vector<data_index_t>& max_shape,
	      const char* fn,
	      bool open_writable);

  static void dynobject_to_membuf(const DynObject&, membuf_t*);
  static void membuf_to_dynobject(const membuf_t& src, DynObject* dest);
};

class FileDataField : public DataField
{
 public:
  FileDataField();
  FileDataField(DynType* value_dyntype,
		const vector<data_index_t>& max_shape,
		const char* fn,
		bool open_writable);
  
  void print(ostream&) const;
  string get_filename() const;  
  void get_value(const vector<data_index_t>& data_coor, DynObject* v) const; 
  void set_value(const vector<data_index_t>& data_coor,
		 const DynObject& value);
  bool is_none_value(const vector<data_index_t>& data_coors) const;
  void allocate_indexes(size_t i_dim, size_t n, 
			vector<data_index_t>* new_indexes);
  void delete_indexes(size_t i_dim, 
		      const vector<data_index_t>& del_indexes);
  void save() const;
  void load(const string& fn, bool open_writable);

 private:
  vector<data_index_t> max_shape;
  string fn;
  int fd;
  size_t nof_set_values;

  void init__(DynType* value_dyntype,
	      const vector<data_index_t>& max_shape,
	      const char* fn,
	      bool open_writable);

  static void dynobject_to_membuf(const DynObject&, membuf_t*);
  static void membuf_to_dynobject(const membuf_t& src, DynObject* dest);
};

#endif
